home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / mac / tkMacScrlbr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  31.8 KB  |  1,058 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkMacScrollbar.c --
  3.  *
  4.  *    This file implements the Macintosh specific portion of the scrollbar
  5.  *    widget.  The Macintosh scrollbar may also draw a windows grow
  6.  *    region under certain cases.
  7.  *
  8.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tkMacScrlbr.c 1.9 96/12/10 20:04:39
  14.  */
  15.  
  16. #include "tkScrollbar.h"
  17. #include "tkMacInt.h"
  18. #include <Controls.h>
  19.  
  20. /*
  21.  * The following definitions should really be in MacOS
  22.  * header files.  They are included here as this is the only
  23.  * file that needs the declarations.
  24.  */
  25. typedef    pascal void (*ThumbActionFunc)(void);
  26.  
  27. #if GENERATINGCFM
  28. typedef UniversalProcPtr ThumbActionUPP;
  29. #else
  30. typedef ThumbActionFunc ThumbActionUPP;
  31. #endif
  32.  
  33. enum {
  34.     uppThumbActionProcInfo = kPascalStackBased
  35. };
  36.  
  37. #if GENERATINGCFM
  38. #define NewThumbActionProc(userRoutine)        \
  39.         (ThumbActionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppThumbActionProcInfo, GetCurrentArchitecture())
  40. #else
  41. #define NewThumbActionProc(userRoutine)        \
  42.         ((ThumbActionUPP) (userRoutine))
  43. #endif
  44.  
  45. /*
  46.  * Minimum slider length, in pixels (designed to make sure that the slider
  47.  * is always easy to grab with the mouse).
  48.  */
  49.  
  50. #define MIN_SLIDER_LENGTH    5
  51.  
  52. /*
  53.  * Declaration of Windows specific scrollbar structure.
  54.  */
  55.  
  56. typedef struct MacScrollbar {
  57.     TkScrollbar info;        /* Generic scrollbar info. */
  58.     ControlRef sbHandle;    /* Handle to the Scrollbar control struct. */
  59.     int macFlags;        /* Various flags; see below. */
  60. } MacScrollbar;
  61.  
  62. /*
  63.  * Flag bits for scrollbars on the Mac:
  64.  * 
  65.  * ALREADY_DEAD:        Non-zero means this scrollbar has been
  66.  *                destroyed, but has not been cleaned up.
  67.  * IN_MODAL_LOOP:        Non-zero means this scrollbar is in the middle
  68.  *                of a modal loop.
  69.  * ACTIVE:            Non-zero means this window is currently
  70.  *                active (in the foreground).
  71.  * FLUSH_TOP:            Flush with top of Mac window.
  72.  * FLUSH_BOTTOM:        Flush with bottom of Mac window.
  73.  * FLUSH_RIGHT:            Flush with right of Mac window.
  74.  * FLUSH_LEFT:            Flush with left of Mac window.
  75.  * SCROLLBAR_GROW:        Non-zero means this window draws the grow
  76.  *                region for the toplevel window.
  77.  * AUTO_ADJUST:            Non-zero means we automatically adjust
  78.  *                the size of the widget to align correctly
  79.  *                along a Mac window.
  80.  * DRAW_GROW:            Non-zero means we draw the grow region.
  81.  */
  82.  
  83. #define ALREADY_DEAD        1
  84. #define IN_MODAL_LOOP        2
  85. #define ACTIVE            4
  86. #define FLUSH_TOP        8
  87. #define FLUSH_BOTTOM        16
  88. #define FLUSH_RIGHT        32
  89. #define FLUSH_LEFT        64
  90. #define SCROLLBAR_GROW        128
  91. #define AUTO_ADJUST        256
  92. #define DRAW_GROW        512
  93.  
  94. /*
  95.  * Globals uses locally in this file.
  96.  */
  97. static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */
  98. static ThumbActionUPP thumbActionProc = NULL;    /* Pointer to func. */
  99. static TkScrollbar *activeScrollPtr = NULL;        /* Non-null when in thumb */
  100.                          /* proc. */
  101. /*
  102.  * Forward declarations for procedures defined later in this file:
  103.  */
  104.  
  105. static pascal void    ScrollbarActionProc _ANSI_ARGS_((ControlRef theControl,
  106.                 ControlPartCode partCode));
  107. static int        ScrollbarBindProc _ANSI_ARGS_((ClientData clientData,
  108.                 Tcl_Interp *interp, XEvent *eventPtr,
  109.                 Tk_Window tkwin, KeySym keySym));
  110. static void        ScrollbarEventProc _ANSI_ARGS_((
  111.                 ClientData clientData, XEvent *eventPtr));
  112. static pascal void    ThumbActionProc _ANSI_ARGS_((void));
  113. static void        UpdateControlValues _ANSI_ARGS_((MacScrollbar *macScrollPtr));
  114.             
  115. /*
  116.  * The class procedure table for the scrollbar widget.
  117.  */
  118.  
  119. TkClassProcs tkpScrollbarProcs = { 
  120.     NULL,            /* createProc. */
  121.     NULL,            /* geometryProc. */
  122.     NULL            /* modalProc */
  123. };
  124.  
  125. /*
  126.  *----------------------------------------------------------------------
  127.  *
  128.  * TkpCreateScrollbar --
  129.  *
  130.  *    Allocate a new TkScrollbar structure.
  131.  *
  132.  * Results:
  133.  *    Returns a newly allocated TkScrollbar structure.
  134.  *
  135.  * Side effects:
  136.  *    None.
  137.  *
  138.  *----------------------------------------------------------------------
  139.  */
  140.  
  141. TkScrollbar *
  142. TkpCreateScrollbar(
  143.     Tk_Window tkwin)    /* New Tk Window. */
  144. {
  145.     MacScrollbar * macScrollPtr;
  146.     TkWindow *winPtr = (TkWindow *)tkwin;
  147.     
  148.     if (scrollActionProc == NULL) {
  149.     scrollActionProc = NewControlActionProc(ScrollbarActionProc);
  150.     thumbActionProc = NewThumbActionProc(ThumbActionProc);
  151.     }
  152.  
  153.     macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar));
  154.     macScrollPtr->sbHandle = NULL;
  155.     macScrollPtr->macFlags = 0;
  156.  
  157.     Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask|
  158.         StructureNotifyMask|FocusChangeMask,
  159.         ScrollbarEventProc, (ClientData) macScrollPtr);
  160.  
  161.     if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
  162.     Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL,
  163.         (ClientData)1);
  164.     TkCreateBindingProcedure(winPtr->mainPtr->interp,
  165.         winPtr->mainPtr->bindingTable,
  166.         (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
  167.         ScrollbarBindProc, NULL, NULL);
  168.     }
  169.  
  170.     return (TkScrollbar *) macScrollPtr;
  171. }
  172.  
  173. /*
  174.  *--------------------------------------------------------------
  175.  *
  176.  * TkpDisplayScrollbar --
  177.  *
  178.  *    This procedure redraws the contents of a scrollbar window.
  179.  *    It is invoked as a do-when-idle handler, so it only runs
  180.  *    when there's nothing else for the application to do.
  181.  *
  182.  * Results:
  183.  *    None.
  184.  *
  185.  * Side effects:
  186.  *    Information appears on the screen.
  187.  *
  188.  *--------------------------------------------------------------
  189.  */
  190.  
  191. void
  192. TkpDisplayScrollbar(
  193.     ClientData clientData)    /* Information about window. */
  194. {
  195.     register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  196.     register MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
  197.     register Tk_Window tkwin = scrollPtr->tkwin;
  198.     
  199.     MacDrawable *macDraw;
  200.     CGrafPtr saveWorld;
  201.     GDHandle saveDevice;
  202.     GWorldPtr destPort;
  203.     WindowRef windowRef;
  204.     
  205.     if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  206.     goto done;
  207.     }
  208.  
  209.     /*
  210.      * Draw the focus or any 3D relief we may have.
  211.      */
  212.     if (scrollPtr->highlightWidth != 0) {
  213.     GC gc;
  214.  
  215.     if (scrollPtr->flags & GOT_FOCUS) {
  216.         gc = Tk_GCForColor(scrollPtr->highlightColorPtr,
  217.             Tk_WindowId(tkwin));
  218.     } else {
  219.         gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr,
  220.             Tk_WindowId(tkwin));
  221.     }
  222.     Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth,
  223.         Tk_WindowId(tkwin));
  224.     }
  225.     Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
  226.         scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  227.         Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
  228.         Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
  229.         scrollPtr->borderWidth, scrollPtr->relief);
  230.  
  231.     /*
  232.      * Set up port for drawing Macintosh control.
  233.      */
  234.     macDraw = (MacDrawable *) Tk_WindowId(tkwin);
  235.     destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin));
  236.     GetGWorld(&saveWorld, &saveDevice);
  237.     SetGWorld(destPort, NULL);
  238.     TkMacSetUpClippingRgn(Tk_WindowId(tkwin));
  239.  
  240.     if (macScrollPtr->sbHandle == NULL) {
  241.         Rect r;
  242.         
  243.         r.left = r.top = 0;
  244.         r.right = r.bottom = 1;
  245.     macScrollPtr->sbHandle = NewControl((WindowRef) destPort, &r, "\p",
  246.         false, (short) 500, 0, 1000,
  247.         scrollBarProc, (SInt32) scrollPtr);
  248.  
  249.     /*
  250.      * If we are foremost than make us active.
  251.      */
  252.     if ((WindowPtr) destPort == FrontWindow()) {
  253.         macScrollPtr->macFlags |= ACTIVE;
  254.     }
  255.     }
  256.  
  257.     /*
  258.      * Update the control values before we draw.
  259.      */
  260.     windowRef  = (**macScrollPtr->sbHandle).contrlOwner;    
  261.     UpdateControlValues(macScrollPtr);
  262.     
  263.     if (macScrollPtr->macFlags & ACTIVE) {
  264.     Draw1Control(macScrollPtr->sbHandle);
  265.     if (macScrollPtr->macFlags & DRAW_GROW) {
  266.         DrawGrowIcon(windowRef);
  267.     }
  268.     } else {
  269.     (**macScrollPtr->sbHandle).contrlHilite = 255;
  270.     Draw1Control(macScrollPtr->sbHandle);
  271.     if (macScrollPtr->macFlags & DRAW_GROW) {
  272.         DrawGrowIcon(windowRef);
  273.         Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
  274.         Tk_Width(tkwin) - 13, Tk_Height(tkwin) - 13,
  275.         Tk_Width(tkwin), Tk_Height(tkwin),
  276.         0, TK_RELIEF_FLAT);
  277.     }
  278.     }
  279.     
  280.     SetGWorld(saveWorld, saveDevice);
  281.      
  282.     done:
  283.     scrollPtr->flags &= ~REDRAW_PENDING;
  284. }
  285.  
  286. /*
  287.  *----------------------------------------------------------------------
  288.  *
  289.  * TkpConfigureScrollbar --
  290.  *
  291.  *    This procedure is called after the generic code has finished
  292.  *    processing configuration options, in order to configure
  293.  *    platform specific options.
  294.  *
  295.  * Results:
  296.  *    None.
  297.  *
  298.  * Side effects:
  299.  *    None.
  300.  *
  301.  *----------------------------------------------------------------------
  302.  */
  303.  
  304. void
  305. TkpConfigureScrollbar(scrollPtr)
  306.     register TkScrollbar *scrollPtr;    /* Information about widget;  may or
  307.                      * may not already have values for
  308.                      * some fields. */
  309. {
  310. }
  311.  
  312. /*
  313.  *----------------------------------------------------------------------
  314.  *
  315.  * TkpComputeScrollbarGeometry --
  316.  *
  317.  *    After changes in a scrollbar's size or configuration, this
  318.  *    procedure recomputes various geometry information used in
  319.  *    displaying the scrollbar.
  320.  *
  321.  * Results:
  322.  *    None.
  323.  *
  324.  * Side effects:
  325.  *    The scrollbar will be displayed differently.
  326.  *
  327.  *----------------------------------------------------------------------
  328.  */
  329.  
  330. void
  331. TkpComputeScrollbarGeometry(
  332.     register TkScrollbar *scrollPtr)    /* Scrollbar whose geometry may
  333.                      * have changed. */
  334. {
  335.     MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
  336.     int width, fieldLength, adjust = 0;
  337.  
  338.     if (scrollPtr->highlightWidth < 0) {
  339.     scrollPtr->highlightWidth = 0;
  340.     }
  341.     scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
  342.     width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
  343.         : Tk_Height(scrollPtr->tkwin);
  344.     scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1;
  345.     fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
  346.         : Tk_Width(scrollPtr->tkwin))
  347.         - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  348.     if (fieldLength < 0) {
  349.     fieldLength = 0;
  350.     }
  351.     scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
  352.     scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
  353.  
  354.     /*
  355.      * Adjust the slider so that some piece of it is always
  356.      * displayed in the scrollbar and so that it has at least
  357.      * a minimal width (so it can be grabbed with the mouse).
  358.      */
  359.  
  360.     if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
  361.     scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
  362.     }
  363.     if (scrollPtr->sliderFirst < 0) {
  364.     scrollPtr->sliderFirst = 0;
  365.     }
  366.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  367.         + MIN_SLIDER_LENGTH)) {
  368.     scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
  369.     }
  370.     if (scrollPtr->sliderLast > fieldLength) {
  371.     scrollPtr->sliderLast = fieldLength;
  372.     }
  373.     scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
  374.     scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
  375.  
  376.     /*
  377.      * Register the desired geometry for the window (leave enough space
  378.      * for the two arrows plus a minimum-size slider, plus border around
  379.      * the whole window, if any).  Then arrange for the window to be
  380.      * redisplayed.
  381.      */
  382.  
  383.     if (scrollPtr->vertical) {
  384.     if ((macScrollPtr->macFlags & AUTO_ADJUST) &&
  385.         (macScrollPtr->macFlags & (FLUSH_RIGHT|FLUSH_LEFT))) {
  386.         adjust--;
  387.     }
  388.     Tk_GeometryRequest(scrollPtr->tkwin,
  389.         scrollPtr->width + 2*scrollPtr->inset + adjust,
  390.         2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  391.         + scrollPtr->inset));
  392.     } else {
  393.     if ((macScrollPtr->macFlags & AUTO_ADJUST) &&
  394.         (macScrollPtr->macFlags & (FLUSH_TOP|FLUSH_BOTTOM))) {
  395.         adjust--;
  396.     }
  397.     Tk_GeometryRequest(scrollPtr->tkwin,
  398.         2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  399.         + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset + adjust);
  400.     }
  401.     Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
  402. }
  403.  
  404. /*
  405.  *----------------------------------------------------------------------
  406.  *
  407.  * TkpDestroyScrollbar --
  408.  *
  409.  *    Free data structures associated with the scrollbar control.
  410.  *
  411.  * Results:
  412.  *    None.
  413.  *
  414.  * Side effects:
  415.  *    None.
  416.  *
  417.  *----------------------------------------------------------------------
  418.  */
  419.  
  420. void
  421. TkpDestroyScrollbar(
  422.     TkScrollbar *scrollPtr)    /* Scrollbar to destroy. */
  423. {
  424.     MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
  425.  
  426.     if (macScrollPtr->sbHandle != NULL) {
  427.     if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) {
  428.         DisposeControl(macScrollPtr->sbHandle);
  429.         macScrollPtr->sbHandle = NULL;
  430.     }
  431.     }
  432.     macScrollPtr->macFlags |= ALREADY_DEAD;
  433. }
  434.  
  435. /*
  436.  *--------------------------------------------------------------
  437.  *
  438.  * TkpScrollbarPosition --
  439.  *
  440.  *    Determine the scrollbar element corresponding to a
  441.  *    given position.
  442.  *
  443.  * Results:
  444.  *    One of TOP_ARROW, TOP_GAP, etc., indicating which element
  445.  *    of the scrollbar covers the position given by (x, y).  If
  446.  *    (x,y) is outside the scrollbar entirely, then OUTSIDE is
  447.  *    returned.
  448.  *
  449.  * Side effects:
  450.  *    None.
  451.  *
  452.  *--------------------------------------------------------------
  453.  */
  454.  
  455. int
  456. TkpScrollbarPosition(
  457.     TkScrollbar *scrollPtr,    /* Scrollbar widget record. */
  458.     int x, int y)        /* Coordinates within scrollPtr's
  459.                  * window. */
  460. {
  461.     MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
  462.     GWorldPtr destPort;
  463.     int length, width, tmp, inactive = false;
  464.     ControlPartCode part;
  465.     Point where;
  466.     Rect bounds;
  467.  
  468.     if (scrollPtr->vertical) {
  469.     length = Tk_Height(scrollPtr->tkwin);
  470.     width = Tk_Width(scrollPtr->tkwin);
  471.     } else {
  472.     tmp = x;
  473.     x = y;
  474.     y = tmp;
  475.     length = Tk_Width(scrollPtr->tkwin);
  476.     width = Tk_Height(scrollPtr->tkwin);
  477.     }
  478.  
  479.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  480.         || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  481.     return OUTSIDE;
  482.     }
  483.  
  484.     /*
  485.      * All of the calculations in this procedure mirror those in
  486.      * DisplayScrollbar.  Be sure to keep the two consistent.  On the 
  487.      * Macintosh we use the OS call TestControl to do this mapping.
  488.      * For TestControl to work, the scrollbar must be active and must
  489.      * be in the current port.
  490.      */
  491.  
  492.     destPort = TkMacGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
  493.     SetGWorld(destPort, NULL);
  494.     UpdateControlValues(macScrollPtr);
  495.     if ((**macScrollPtr->sbHandle).contrlHilite == 255) {
  496.     inactive = true;
  497.     (**macScrollPtr->sbHandle).contrlHilite = 0;
  498.     }
  499.  
  500.     TkMacWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);        
  501.     where.h = x + bounds.left;
  502.     where.v = y + bounds.top;
  503.     part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where);
  504.     if (inactive) {
  505.     (**macScrollPtr->sbHandle).contrlHilite = 255;
  506.     }
  507.     switch (part) {
  508.         case inUpButton:
  509.         return TOP_ARROW;
  510.         case inPageUp:
  511.         return TOP_GAP;
  512.         case inThumb:
  513.         return SLIDER;
  514.         case inPageDown:
  515.         return BOTTOM_GAP;
  516.         case inDownButton:
  517.         return BOTTOM_ARROW;
  518.         default:
  519.         return OUTSIDE;
  520.     }
  521. }
  522.  
  523. /*
  524.  *--------------------------------------------------------------
  525.  *
  526.  * ThumbActionProc --
  527.  *
  528.  *    Callback procedure used by the Macintosh toolbox call
  529.  *    TrackControl.  This call is used to track the thumb of
  530.  *    the scrollbar.  Unlike the ScrollbarActionProc function
  531.  *    this function is called once and basically takes over
  532.  *    tracking the scrollbar from the control.  This is done
  533.  *    to avoid conflicts with what the control plans to draw.
  534.  *
  535.  * Results:
  536.  *    None.
  537.  *
  538.  * Side effects:
  539.  *    May change the display.
  540.  *
  541.  *--------------------------------------------------------------
  542.  */
  543.  
  544. static pascal void
  545. ThumbActionProc()
  546. {
  547.     register TkScrollbar *scrollPtr = activeScrollPtr;
  548.     register MacScrollbar *macScrollPtr = (MacScrollbar *) activeScrollPtr;
  549.     Tcl_DString cmdString;
  550.     Rect nullRect = {0,0,0,0};
  551.     int origValue, trackBarPin;
  552.     double thumbWidth, newFirstFraction, trackBarSize;
  553.     char vauleString[40];
  554.     Point currentPoint = { 0, 0 };
  555.     Point lastPoint = { 0, 0 };
  556.     Rect trackRect;
  557.     Tcl_Interp *interp;
  558.     
  559.     if (scrollPtr == NULL) {
  560.     return;
  561.     }
  562.  
  563.     Tcl_DStringInit(&cmdString);
  564.     
  565.     /*
  566.      * First compute values that will remain constant during the tracking
  567.      * of the thumb.  The variable trackBarSize is the length of the scrollbar
  568.      * minus the 2 arrows and half the width of the thumb on both sides
  569.      * (3 * arrowLength).  The variable trackBarPin is the lower starting point
  570.      * of the drag region.
  571.      *
  572.      * Note: the arrowLength is equal to the thumb width of a Mac scrollbar.
  573.      */
  574.     origValue = GetControlValue(macScrollPtr->sbHandle);
  575.     trackRect = (**macScrollPtr->sbHandle).contrlRect;
  576.     if (scrollPtr->vertical == true) {
  577.     trackBarSize = (double) (trackRect.bottom - trackRect.top
  578.         - (scrollPtr->arrowLength * 3));
  579.     trackBarPin = trackRect.top + scrollPtr->arrowLength
  580.         + (scrollPtr->arrowLength / 2);
  581.     InsetRect(&trackRect, -25, -113);
  582.     
  583.     } else {
  584.     trackBarSize = (double) (trackRect.right - trackRect.left
  585.         - (scrollPtr->arrowLength * 3));
  586.     trackBarPin = trackRect.left + scrollPtr->arrowLength
  587.         + (scrollPtr->arrowLength / 2);
  588.     InsetRect(&trackRect, -113, -25);
  589.     }
  590.  
  591.     /*
  592.      * Track the mouse while the button is held down.  If the mouse is moved,
  593.      * we calculate the value that should be passed to the "command" part of
  594.      * the scrollbar.
  595.      */
  596.     while (StillDown()) {
  597.     GetMouse(¤tPoint);
  598.     if (EqualPt(currentPoint, lastPoint)) {
  599.         continue;
  600.     }
  601.     lastPoint = currentPoint;
  602.  
  603.     /*
  604.      * Calculating this value is a little tricky.  We need to calculate a
  605.      * value for where the thumb would be in a Motif widget (variable
  606.      * thumb).  This value is what the "command" expects and is what will
  607.      * be resent to the scrollbar to update its value.
  608.      */
  609.     thumbWidth = scrollPtr->lastFraction - scrollPtr->firstFraction;
  610.     if (PtInRect(currentPoint, &trackRect)) {
  611.         if (scrollPtr->vertical == true) {
  612.         newFirstFraction =  (1.0 - thumbWidth) *
  613.             ((double) (currentPoint.v - trackBarPin) / trackBarSize);
  614.         } else {
  615.         newFirstFraction =  (1.0 - thumbWidth) *
  616.             ((double) (currentPoint.h - trackBarPin) / trackBarSize);
  617.         }
  618.     } else {
  619.         newFirstFraction = ((double) origValue / 1000.0)
  620.         * (1.0 - thumbWidth);
  621.     }
  622.     
  623.     sprintf(vauleString, "%g", newFirstFraction);
  624.  
  625.     Tcl_DStringSetLength(&cmdString, 0);
  626.     Tcl_DStringAppend(&cmdString, scrollPtr->command,
  627.         scrollPtr->commandSize);
  628.     Tcl_DStringAppendElement(&cmdString, "moveto");
  629.     Tcl_DStringAppendElement(&cmdString, vauleString);
  630.  
  631.         interp = scrollPtr->interp;
  632.         Tcl_Preserve((ClientData) interp);
  633.     Tcl_GlobalEval(interp, cmdString.string);
  634.         Tcl_Release((ClientData) interp);
  635.     
  636.     Tcl_DStringSetLength(&cmdString, 0);
  637.     Tcl_DStringAppend(&cmdString, "update idletasks",
  638.         strlen("update idletasks"));
  639.         Tcl_Preserve((ClientData) interp);
  640.     Tcl_GlobalEval(interp, cmdString.string);
  641.         Tcl_Release((ClientData) interp);
  642.     }
  643.     
  644.     /*
  645.      * This next bit of code is a bit of a hack - but needed.  The problem is
  646.      * that the control wants to draw the drag outline if the control value
  647.      * changes during the drag (which it does).  What we do here is change the
  648.      * clip region to hide this drawing from the user.
  649.      */
  650.     ClipRect(&nullRect);
  651.     
  652.     Tcl_DStringFree(&cmdString);
  653.     return;
  654. }
  655.  
  656. /*
  657.  *--------------------------------------------------------------
  658.  *
  659.  * ScrollbarActionProc --
  660.  *
  661.  *    Callback procedure used by the Macintosh toolbox call
  662.  *    TrackControl.  This call will update the display while
  663.  *    the scrollbar is being manipulated by the user.
  664.  *
  665.  * Results:
  666.  *    None.
  667.  *
  668.  * Side effects:
  669.  *    May change the display.
  670.  *
  671.  *--------------------------------------------------------------
  672.  */
  673.  
  674. static pascal void
  675. ScrollbarActionProc(
  676.     ControlRef theControl,     /* Handle to scrollbat control */
  677.     ControlPartCode partCode)    /* Part of scrollbar that was "hit" */
  678. {
  679.     register TkScrollbar *scrollPtr = (TkScrollbar *) GetCRefCon(theControl);
  680.     Tcl_DString cmdString;
  681.     
  682.     Tcl_DStringInit(&cmdString);
  683.     Tcl_DStringAppend(&cmdString, scrollPtr->command,
  684.         scrollPtr->commandSize);
  685.  
  686.     if (partCode == inUpButton || partCode == inDownButton) {
  687.     Tcl_DStringAppendElement(&cmdString, "scroll");
  688.     Tcl_DStringAppendElement(&cmdString,
  689.         (partCode == inUpButton ) ? "-1" : "1");
  690.     Tcl_DStringAppendElement(&cmdString, "unit");
  691.     } else if (partCode == inPageUp || partCode == inPageDown) {
  692.     Tcl_DStringAppendElement(&cmdString, "scroll");
  693.     Tcl_DStringAppendElement(&cmdString,
  694.         (partCode == inPageUp ) ? "-1" : "1");
  695.     Tcl_DStringAppendElement(&cmdString, "page");
  696.     }
  697.     Tcl_Preserve((ClientData) scrollPtr->interp);
  698.     Tcl_DStringAppend(&cmdString, "; update idletasks",
  699.     strlen("; update idletasks"));
  700.     Tcl_GlobalEval(scrollPtr->interp, cmdString.string);
  701.     Tcl_Release((ClientData) scrollPtr->interp);
  702.  
  703.     Tcl_DStringFree(&cmdString);
  704. }
  705.  
  706. /*
  707.  *--------------------------------------------------------------
  708.  *
  709.  * ScrollbarBindProc --
  710.  *
  711.  *    This procedure is invoked when the default <ButtonPress>
  712.  *    binding on the Scrollbar bind tag fires.
  713.  *
  714.  * Results:
  715.  *    None.
  716.  *
  717.  * Side effects:
  718.  *    The event enters a modal loop.
  719.  *
  720.  *--------------------------------------------------------------
  721.  */
  722.  
  723. static int
  724. ScrollbarBindProc(
  725.     ClientData clientData,    /* Not used. */
  726.     Tcl_Interp *interp,        /* Interp with binding. */
  727.     XEvent *eventPtr,        /* X event that triggered binding. */
  728.     Tk_Window tkwin,        /* Target window for event. */
  729.     KeySym keySym)        /* The KeySym if a key event. */
  730. {
  731.     TkWindow *winPtr = (TkWindow*)tkwin;
  732.     TkScrollbar *scrollPtr = (TkScrollbar *) winPtr->instanceData;
  733.     MacScrollbar *macScrollPtr = (MacScrollbar *) winPtr->instanceData;
  734.  
  735.     Tcl_Preserve((ClientData)scrollPtr);
  736.     macScrollPtr->macFlags |= IN_MODAL_LOOP;
  737.     
  738.     if (eventPtr->type == ButtonPress) {
  739.         Point where;
  740.         Rect bounds;
  741.         int part, x, y, dummy;
  742.         unsigned int state;
  743.     CGrafPtr saveWorld;
  744.     GDHandle saveDevice;
  745.     GWorldPtr destPort;
  746.     Window window;
  747.  
  748.     /*
  749.      * To call Macintosh control routines we must have the port
  750.      * set to the window containing the control.  We will then test
  751.      * which part of the control was hit and act accordingly.
  752.      */
  753.     destPort = TkMacGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
  754.     GetGWorld(&saveWorld, &saveDevice);
  755.     SetGWorld(destPort, NULL);
  756.     TkMacSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin));
  757.  
  758.     TkMacWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);        
  759.         where.h = eventPtr->xbutton.x + bounds.left;
  760.         where.v = eventPtr->xbutton.y + bounds.top;
  761.     part = TestControl(macScrollPtr->sbHandle, where);
  762.     if (part == inThumb && scrollPtr->jump == false) {
  763.         /*
  764.          * Case 1: In thumb, no jump scrolling.  Call track control
  765.          * with the thumb action proc which will do most of the work.
  766.          * Set the global activeScrollPtr to the current control
  767.          * so the callback may have access to it.
  768.          */
  769.         activeScrollPtr = scrollPtr;
  770.         part = TrackControl(macScrollPtr->sbHandle, where,
  771.             (ControlActionUPP) thumbActionProc);
  772.         activeScrollPtr = NULL;
  773.     } else if (part == inThumb) {
  774.         /*
  775.          * Case 2: in thumb with jump scrolling.  Call TrackControl
  776.          * with a NULL action proc.  Use the new value of the control
  777.          * to set update the control.
  778.          */
  779.         part = TrackControl(macScrollPtr->sbHandle, where, NULL);
  780.         if (part == inThumb) {
  781.             double newFirstFraction, thumbWidth;
  782.         Tcl_DString cmdString;
  783.         char vauleString[TCL_DOUBLE_SPACE];
  784.  
  785.         /*
  786.          * The following calculation takes the new control
  787.          * value and maps it to what Tk needs for its variable
  788.          * thumb size representation.
  789.          */
  790.         thumbWidth = scrollPtr->lastFraction
  791.              - scrollPtr->firstFraction;
  792.         newFirstFraction = (1.0 - thumbWidth) *
  793.             ((double) GetControlValue(macScrollPtr->sbHandle) / 1000.0);
  794.         sprintf(vauleString, "%g", newFirstFraction);
  795.  
  796.         Tcl_DStringInit(&cmdString);
  797.         Tcl_DStringAppend(&cmdString, scrollPtr->command,
  798.             strlen(scrollPtr->command));
  799.         Tcl_DStringAppendElement(&cmdString, "moveto");
  800.         Tcl_DStringAppendElement(&cmdString, vauleString);
  801.         Tcl_DStringAppend(&cmdString, "; update idletasks",
  802.             strlen("; update idletasks"));
  803.         
  804.                 interp = scrollPtr->interp;
  805.                 Tcl_Preserve((ClientData) interp);
  806.         Tcl_GlobalEval(interp, cmdString.string);
  807.                 Tcl_Release((ClientData) interp);
  808.         Tcl_DStringFree(&cmdString);        
  809.         }
  810.     } else if (part != 0) {
  811.         /*
  812.          * Case 3: in any other part of the scrollbar.  We call
  813.          * TrackControl with the scrollActionProc which will do
  814.          * most all the work.
  815.          */
  816.         TrackControl(macScrollPtr->sbHandle, where, scrollActionProc);
  817.         HiliteControl(macScrollPtr->sbHandle, 0);
  818.     }
  819.     
  820.     /*
  821.      * The TrackControl call will "eat" the ButtonUp event.  We now
  822.      * generate a ButtonUp event so Tk will unset implicit grabs etc.
  823.      */
  824.     GetMouse(&where);
  825.     XQueryPointer(NULL, None, &window, &window, &x,
  826.         &y, &dummy, &dummy, &state);
  827.     window = Tk_WindowId(scrollPtr->tkwin);
  828.     TkGenerateButtonEvent(x, y, window, state);
  829.  
  830.     SetGWorld(saveWorld, saveDevice);
  831.     }
  832.  
  833.     if (macScrollPtr->sbHandle && (macScrollPtr->macFlags & ALREADY_DEAD)) {
  834.     DisposeControl(macScrollPtr->sbHandle);
  835.     macScrollPtr->sbHandle = NULL;
  836.     }
  837.     macScrollPtr->macFlags &= ~IN_MODAL_LOOP;
  838.     Tcl_Release((ClientData)scrollPtr);
  839.     
  840.     return TCL_OK;
  841. }
  842.  
  843. /*
  844.  *--------------------------------------------------------------
  845.  *
  846.  * ScrollbarEventProc --
  847.  *
  848.  *    This procedure is invoked by the Tk dispatcher for various
  849.  *    events on scrollbars.
  850.  *
  851.  * Results:
  852.  *    None.
  853.  *
  854.  * Side effects:
  855.  *    When the window gets deleted, internal structures get
  856.  *    cleaned up.  When it gets exposed, it is redisplayed.
  857.  *
  858.  *--------------------------------------------------------------
  859.  */
  860.  
  861. static void
  862. ScrollbarEventProc(
  863.     ClientData clientData,    /* Information about window. */
  864.     XEvent *eventPtr)        /* Information about event. */
  865. {
  866.     TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  867.     MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
  868.  
  869.     if (eventPtr->type == UnmapNotify) {
  870.     TkMacSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false);
  871.     } else if (eventPtr->type == ActivateNotify) {
  872.     macScrollPtr->macFlags |= ACTIVE;
  873.     TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
  874.     } else if (eventPtr->type == DeactivateNotify) {
  875.     macScrollPtr->macFlags &= ~ACTIVE;
  876.     TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
  877.     } else {
  878.     TkScrollbarEventProc(clientData, eventPtr);
  879.     }
  880. }
  881.  
  882. /*
  883.  *--------------------------------------------------------------
  884.  *
  885.  * UpdateControlValues --
  886.  *
  887.  *    This procedure updates the Macintosh scrollbar control
  888.  *    to display the values defined by the Tk scrollbar.
  889.  *
  890.  * Results:
  891.  *    None.
  892.  *
  893.  * Side effects:
  894.  *    The Macintosh control is updated.
  895.  *
  896.  *--------------------------------------------------------------
  897.  */
  898.  
  899. static void
  900. UpdateControlValues(
  901.     MacScrollbar *macScrollPtr)        /* Scrollbar data struct. */
  902. {
  903.     TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr;
  904.     Tk_Window tkwin = scrollPtr->tkwin;
  905.     MacDrawable * macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
  906.     WindowRef windowRef  = (**macScrollPtr->sbHandle).contrlOwner;    
  907.     double middle;
  908.     int drawGrowRgn = false;
  909.     int flushRight = false;
  910.     int flushBottom = false;
  911.  
  912.     /*
  913.      * We can't use the Macintosh commands SizeControl and MoveControl as these
  914.      * calls will also cause a redraw which in our case will also cause
  915.      * flicker.  To avoid this we adjust the control record directly.  The
  916.      * Draw1Control command appears to just draw where ever the control says to
  917.      * draw so this seems right.
  918.      *
  919.      * NOTE: changing the control record directly may not work when
  920.      * Apple releases the Copland version of the MacOS (or when hell is cold).
  921.      */
  922.      
  923.     (**macScrollPtr->sbHandle).contrlRect.left = macDraw->xOff + scrollPtr->inset;
  924.     (**macScrollPtr->sbHandle).contrlRect.top = macDraw->yOff + scrollPtr->inset;
  925.     (**macScrollPtr->sbHandle).contrlRect.right = macDraw->xOff + Tk_Width(tkwin)
  926.     - scrollPtr->inset;
  927.     (**macScrollPtr->sbHandle).contrlRect.bottom = macDraw->yOff +
  928.     Tk_Height(tkwin) - scrollPtr->inset;
  929.     
  930.     /*
  931.      * To make Tk applications look more like Macintosh applications without 
  932.      * requiring additional work by the Tk developer we do some cute tricks.
  933.      * The first trick plays with the size of the widget to get it to overlap
  934.      * with the side of the window by one pixel (we don't do this if the placer
  935.      * is the geometry manager).  The second trick shrinks the scrollbar if it
  936.      * it covers the area of the grow region ao the scrollbar can also draw
  937.      * the grow region if need be.
  938.      */
  939.     if (!strcmp(macDraw->winPtr->geomMgrPtr->name, "place")) {
  940.     macScrollPtr->macFlags &= AUTO_ADJUST;
  941.     } else {
  942.     macScrollPtr->macFlags |= AUTO_ADJUST;
  943.     }
  944.     /* TODO: use accessor function!!! */
  945.     if (windowRef->portRect.left == (**macScrollPtr->sbHandle).contrlRect.left) {
  946.     if (macScrollPtr->macFlags & AUTO_ADJUST) {
  947.         (**macScrollPtr->sbHandle).contrlRect.left--;
  948.     }
  949.     if (!(macScrollPtr->macFlags & FLUSH_LEFT)) {
  950.         macScrollPtr->macFlags |= FLUSH_LEFT;
  951.         if (scrollPtr->vertical) {
  952.         TkpComputeScrollbarGeometry(scrollPtr);
  953.         }
  954.     }
  955.     } else if (macScrollPtr->macFlags & FLUSH_LEFT) {
  956.     macScrollPtr->macFlags &= ~FLUSH_LEFT;
  957.     if (scrollPtr->vertical) {
  958.         TkpComputeScrollbarGeometry(scrollPtr);
  959.     }
  960.     }
  961.     
  962.     if (windowRef->portRect.top == (**macScrollPtr->sbHandle).contrlRect.top) {
  963.     if (macScrollPtr->macFlags & AUTO_ADJUST) {
  964.         (**macScrollPtr->sbHandle).contrlRect.top--;
  965.     }
  966.     if (!(macScrollPtr->macFlags & FLUSH_TOP)) {
  967.         macScrollPtr->macFlags |= FLUSH_TOP;
  968.         if (! scrollPtr->vertical) {
  969.         TkpComputeScrollbarGeometry(scrollPtr);
  970.         }
  971.     }
  972.     } else if (macScrollPtr->macFlags & FLUSH_TOP) {
  973.     macScrollPtr->macFlags &= ~FLUSH_TOP;
  974.     if (! scrollPtr->vertical) {
  975.         TkpComputeScrollbarGeometry(scrollPtr);
  976.     }
  977.     }
  978.     
  979.     if (windowRef->portRect.right == (**macScrollPtr->sbHandle).contrlRect.right) {
  980.     flushRight = true;
  981.     if (macScrollPtr->macFlags & AUTO_ADJUST) {
  982.         (**macScrollPtr->sbHandle).contrlRect.right++;
  983.     }
  984.     if (!(macScrollPtr->macFlags & FLUSH_RIGHT)) {
  985.         macScrollPtr->macFlags |= FLUSH_RIGHT;
  986.         if (scrollPtr->vertical) {
  987.         TkpComputeScrollbarGeometry(scrollPtr);
  988.         }
  989.     }
  990.     } else if (macScrollPtr->macFlags & FLUSH_RIGHT) {
  991.     macScrollPtr->macFlags &= ~FLUSH_RIGHT;
  992.     if (scrollPtr->vertical) {
  993.         TkpComputeScrollbarGeometry(scrollPtr);
  994.     }
  995.     }
  996.     
  997.     if (windowRef->portRect.bottom == (**macScrollPtr->sbHandle).contrlRect.bottom) {
  998.     flushBottom = true;
  999.     if (macScrollPtr->macFlags & AUTO_ADJUST) {
  1000.         (**macScrollPtr->sbHandle).contrlRect.bottom++;
  1001.     }
  1002.     if (!(macScrollPtr->macFlags & FLUSH_BOTTOM)) {
  1003.         macScrollPtr->macFlags |= FLUSH_BOTTOM;
  1004.         if (! scrollPtr->vertical) {
  1005.         TkpComputeScrollbarGeometry(scrollPtr);
  1006.         }
  1007.     }
  1008.     } else if (macScrollPtr->macFlags & FLUSH_BOTTOM) {
  1009.     macScrollPtr->macFlags &= ~FLUSH_BOTTOM;
  1010.     if (! scrollPtr->vertical) {
  1011.         TkpComputeScrollbarGeometry(scrollPtr);
  1012.     }
  1013.     }
  1014.  
  1015.     /*
  1016.      * If the scrollbar is flush against the bottom right hand coner then
  1017.      * it may need to draw the grow region for the window so we let the
  1018.      * wm code know about this scrollbar.  We don't actually draw the grow
  1019.      * region, however, unless we are currently resizable.
  1020.      */
  1021.     macScrollPtr->macFlags &= ~DRAW_GROW;
  1022.     if (flushBottom && flushRight) {
  1023.     TkMacSetScrollbarGrow((TkWindow *) tkwin, true);
  1024.     if (TkMacResizable(macDraw->toplevel->winPtr)) {
  1025.         if (scrollPtr->vertical) {
  1026.         (**macScrollPtr->sbHandle).contrlRect.bottom -= 14;
  1027.         } else {
  1028.         (**macScrollPtr->sbHandle).contrlRect.right -= 14;
  1029.         }
  1030.         macScrollPtr->macFlags |= DRAW_GROW;
  1031.     }
  1032.     } else {
  1033.     TkMacSetScrollbarGrow((TkWindow *) tkwin, false);
  1034.     }
  1035.     
  1036.     /*
  1037.      * Given the Tk parameters for the fractions of the start and
  1038.      * end of the thumb, the following calculation determines the
  1039.      * location for the fixed sized Macintosh thumb.
  1040.      */
  1041.     middle = scrollPtr->firstFraction / (scrollPtr->firstFraction +
  1042.         (1.0 - scrollPtr->lastFraction));
  1043.  
  1044.     (**macScrollPtr->sbHandle).contrlValue = (short) (middle * 1000);
  1045.     if ((**macScrollPtr->sbHandle).contrlHilite == 0 || 
  1046.         (**macScrollPtr->sbHandle).contrlHilite == 255) {
  1047.     if (scrollPtr->firstFraction == 0.0 &&
  1048.         scrollPtr->lastFraction == 1.0) {
  1049.         (**macScrollPtr->sbHandle).contrlHilite = 255;
  1050.     } else {
  1051.         (**macScrollPtr->sbHandle).contrlHilite = 0;
  1052.     }
  1053.     }
  1054.     if ((**macScrollPtr->sbHandle).contrlVis != 255) {
  1055.     (**macScrollPtr->sbHandle).contrlVis = 255;
  1056.     }
  1057. }
  1058.